#pragma once
#include <zCoreConfig.hpp>
#include "../common.hpp"
#include "../Utility/StringTools.hpp"
#include <3rdparty/rapidxml/rapidxml.hpp>

namespace zzz{
class RapidXML;
class ZCORE_CLASS RapidXMLNode {
public:
  RapidXMLNode(const RapidXMLNode &node);
  explicit RapidXMLNode(rapidxml::xml_node<> *node, const RapidXML *root);

  bool IsValid() const;
  bool SetName(const string &name);

  RapidXMLNode GetParent();

  zuint NodeNumber() const;
  RapidXMLNode GetNode(zuint i);
  RapidXMLNode GetNode(const string &name);
  RapidXMLNode AppendNode(const string &name);
  bool HasNode(const string &name);
  bool RemoveNode(const string &name);
  bool RemoveNode(zuint i);

  //iteration
  RapidXMLNode GetFirstNode(const string &name=string());
  RapidXMLNode GetNextSibling(const string &name=string());
  void GotoNextSibling(const string &name=string());
  void operator++();

  bool HasAttribute(const string &name) const;
  const char *GetAttribute(const string &name, const char *missing=NULL) const;
  template<typename T>bool GetAttribute(const string &name, T& value) const
  {
    const string &str=GetAttribute(name);
    value = FromString<T>(str);
    return true;
  }
  bool SetAttribute(const string &name, const char *value) const;
  bool SetAttribute(const string &name, const string &value) const;
  template<typename T>
  bool SetAttribute(const string &name, const T &value) const {
    return SetAttribute(name,ToString(value));
  }
  bool RemoveAttribute(const string &name);

  const char *GetText() const;
  bool SetText(const char *text) const;
  bool SetText(const string &text) const;
  bool RemoveText();
  const char *GetName() const;

  const RapidXML *root_;
protected:
  rapidxml::xml_node<>* node_;
};

//input text
inline const RapidXMLNode& operator<<(const RapidXMLNode &node, const char *text)
{
  node.SetText(text);
  return node;
}

inline const RapidXMLNode& operator<<(const RapidXMLNode &node, const string &text)
{
  node.SetText(text.c_str());
  return node;
}

//input attribute
template<typename T>
inline const RapidXMLNode& operator<<(const RapidXMLNode &node, const T &text)
{
  node.SetText(ToString(text).c_str());
  return node;
}

inline const RapidXMLNode& operator<<(const RapidXMLNode &node, const pair<const char *, const char *> &attrib)
{
  node.SetAttribute(attrib.first, attrib.second);
  return node;
}

inline const RapidXMLNode& operator<<(const RapidXMLNode &node, const pair<const char *, const string> &attrib)
{
  node.SetAttribute(attrib.first, attrib.second.c_str());
  return node;
}

template<typename T>
inline const RapidXMLNode& operator<<(const RapidXMLNode &node, const pair<const char *, T> &attrib)
{
  node.SetAttribute(attrib.first, ToString(attrib.second).c_str());
  return node;
}

inline const RapidXMLNode& operator<<(const RapidXMLNode &node, const pair<const string, const char *> &attrib)
{
  node.SetAttribute(attrib.first, attrib.second);
  return node;
}

inline const RapidXMLNode& operator<<(const RapidXMLNode &node, const pair<const string, const string> &attrib)
{
  node.SetAttribute(attrib.first, attrib.second.c_str());
  return node;
}

template<typename T>
inline const RapidXMLNode& operator<<(const RapidXMLNode &node, const pair<const string, T> &attrib)
{
  node.SetAttribute(attrib.first, ToString(attrib.second).c_str());
  return node;
}


}
